<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"><title>码行 - 与你同行</title><meta name="author" content="Carl Su"><meta name="copyright" content="Carl Su"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="ffffff"><meta name="description" content="纸上得来终觉浅，绝知此事要躬行。">
<meta property="og:type" content="website">
<meta property="og:title" content="码行">
<meta property="og:url" content="https://devsu.top/page/10/index.html">
<meta property="og:site_name" content="码行">
<meta property="og:description" content="纸上得来终觉浅，绝知此事要躬行。">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://s2.loli.net/2023/03/09/QrI9mgJ4XlbEPzN.png">
<meta property="article:author" content="Carl Su">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://s2.loli.net/2023/03/09/QrI9mgJ4XlbEPzN.png"><link rel="shortcut icon" href="https://s2.loli.net/2023/03/09/whMHdYkrKoIBnSC.png"><link rel="canonical" href="https://devsu.top/page/10/index.html"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//hm.baidu.com"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/node-snackbar/dist/snackbar.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox.min.css" media="print" onload="this.media='all'"><script>var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "https://hm.baidu.com/hm.js?6243425e2ecb037931274c4ca1db3132";
  var s = document.getElementsByTagName("script")[0]; 
  s.parentNode.insertBefore(hm, s);
})();
</script><script>const GLOBAL_CONFIG = { 
  root: '/',
  algolia: undefined,
  localSearch: {"path":"/search.xml","preload":true,"languages":{"hits_empty":"找不到您查询的内容：${query}"}},
  translate: {"defaultEncoding":2,"translateDelay":0,"msgToTraditionalChinese":"繁","msgToSimplifiedChinese":"简"},
  noticeOutdate: undefined,
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":300},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '天',
  date_suffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: {"limitCount":50,"languages":{"author":"作者: Carl Su","link":"链接: ","source":"来源: 码行","info":"著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。"}},
  lightbox: 'fancybox',
  Snackbar: {"chs_to_cht":"你已切换为繁体","cht_to_chs":"你已切换为简体","day_to_night":"你已切换为深色模式","night_to_day":"你已切换为浅色模式","bgLight":"#49b1f5","bgDark":"#1f1f1f","position":"bottom-left"},
  source: {
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.css'
    }
  },
  isPhotoFigcaption: true,
  islazyload: true,
  isAnchor: false,
  percent: {
    toc: true,
    rightside: true,
  }
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
  title: '码行',
  isPost: false,
  isHome: true,
  isHighlightShrink: false,
  isToc: false,
  postUpdate: '2023-03-30 10:59:02'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
    win.getCSS = (url,id = false) => new Promise((resolve, reject) => {
      const link = document.createElement('link')
      link.rel = 'stylesheet'
      link.href = url
      if (id) link.id = id
      link.onerror = reject
      link.onload = link.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        link.onload = link.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(link)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', 'ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          const now = new Date()
          const hour = now.getHours()
          const isNight = hour <= 6 || hour >= 18
          if (t === undefined) isNight ? activateDarkMode() : activateLightMode()
          else if (t === 'light') activateLightMode()
          else activateDarkMode()
        
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    
    const detectApple = () => {
      if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
        document.documentElement.classList.add('apple')
      }
    }
    detectApple()
    })(window)</script><meta name="generator" content="Hexo 6.3.0"></head><body><div id="loading-box"><div class="loading-left-bg"></div><div class="loading-right-bg"></div><div class="spinner-box"><div class="configure-border-1"><div class="configure-core"></div></div><div class="configure-border-2"><div class="configure-core"></div></div><div class="loading-word">加载中...</div></div></div><script>const preloader = {
  endLoading: () => {
    document.body.style.overflow = 'auto';
    document.getElementById('loading-box').classList.add("loaded")
  },
  initLoading: () => {
    document.body.style.overflow = '';
    document.getElementById('loading-box').classList.remove("loaded")

  }
}
window.addEventListener('load',()=> { preloader.endLoading() })

if (false) {
  document.addEventListener('pjax:send', () => { preloader.initLoading() })
  document.addEventListener('pjax:complete', () => { preloader.endLoading() })
}</script><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src="https://s2.loli.net/2023/03/09/QrI9mgJ4XlbEPzN.png" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="sidebar-site-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">169</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">37</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">38</div></a></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 归档</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> 清单</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/music/"><i class="fa-fw fas fa-music"></i><span> 音乐</span></a></li><li><a class="site-page child" href="/Gallery/"><i class="fa-fw fas fa-images"></i><span> 照片</span></a></li><li><a class="site-page child" href="/movies/"><i class="fa-fw fas fa-video"></i><span> 电影</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div></div></div><div class="page" id="body-wrap"><header class="full_page fixed" id="page-header" style="background-image: url('https://s2.loli.net/2023/03/09/JQOG5BtENjoCvYl.jpg')"><nav id="nav"><span id="blog-info"><a href="/" title="码行"><img class="site-icon" src="https://s2.loli.net/2023/03/09/whMHdYkrKoIBnSC.png"/><span class="site-name">码行</span></a></span><div id="menus"><div id="search-button"><a class="site-page social-icon search" href="javascript:void(0);"><i class="fas fa-search fa-fw"></i><span> 搜索</span></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 归档</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> 清单</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/music/"><i class="fa-fw fas fa-music"></i><span> 音乐</span></a></li><li><a class="site-page child" href="/Gallery/"><i class="fa-fw fas fa-images"></i><span> 照片</span></a></li><li><a class="site-page child" href="/movies/"><i class="fa-fw fas fa-video"></i><span> 电影</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div><div id="toggle-menu"><a class="site-page" href="javascript:void(0);"><i class="fas fa-bars fa-fw"></i></a></div></div></nav><div id="site-info"><h1 id="site-title">码行</h1><div id="site-subtitle"><span id="subtitle"></span></div><div id="site_social_icons"><a class="social-icon" href="https://github.com/winstone-su" target="_blank" title="Github"><i class="fab fa-github"></i></a><a class="social-icon" href="mailto:winstone.su@gmail.com" target="_blank" title="Email"><i class="fas fa-envelope"></i></a></div></div><div id="scroll-down"><i class="fas fa-angle-down scroll-down-effects"></i></div></header><main class="layout" id="content-inner"><div class="recent-posts" id="recent-posts"><div class="recent-post-item"><div class="post_cover left"><a href="/posts/c9b7198f/" title="Jekyll 运行错误"><img class="post-bg" src="https://p8.itc.cn/images01/20210924/7e6dfdde02fc426ba281d529eb67fbe8.jpeg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Jekyll 运行错误"></a></div><div class="recent-post-info"><a class="article-title" href="/posts/c9b7198f/" title="Jekyll 运行错误">Jekyll 运行错误</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time class="post-meta-date-created" datetime="2022-07-10T11:59:14.000Z" title="发表于 2022-07-10 19:59:14">2022-07-10</time><span class="article-meta-separator">|</span><i class="fas fa-history"></i><span class="article-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2023-03-15T07:40:55.363Z" title="更新于 2023-03-15 15:40:55">2023-03-15</time></span><span class="article-meta"><span class="article-meta-separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/categories/Jekyll/">Jekyll</a></span><span class="article-meta tags"><span class="article-meta-separator">|</span><i class="fas fa-tag"></i><a class="article-meta__tags" href="/tags/Jekyll/">Jekyll</a></span></div><div class="content">Jekyll 运行时发生错误:
/Library/Ruby/Gems/2.6.0/gems/bundler-2.1.4/lib/bundler/runtime.rb:312:in `check_for_activated_spec!&#x27;:You have already activated i18n 1.8.3, but your Gemfile requires i18n 0.9.5.Prepending `bundle exec` to your command may solve this. (Gem::LoadError)

​	解决办法:
bundle update

 修改 Gemfile.lock 将 i18n 配置升级为1.8.3
bundle exec jekyll serve

再次运行项目
</div></div></div><div class="recent-post-item"><div class="post_cover right"><a href="/posts/be9f17d6/" title="Kotlin编程第一课(目录)"><img class="post-bg" src="https://img2.baidu.com/it/u=3956021957,3313212296&amp;fm=253&amp;fmt=auto&amp;app=138&amp;f=JPEG?w=800&amp;h=500" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Kotlin编程第一课(目录)"></a></div><div class="recent-post-info"><a class="article-title" href="/posts/be9f17d6/" title="Kotlin编程第一课(目录)">Kotlin编程第一课(目录)</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time class="post-meta-date-created" datetime="2022-07-10T07:34:08.000Z" title="发表于 2022-07-10 15:34:08">2022-07-10</time><span class="article-meta-separator">|</span><i class="fas fa-history"></i><span class="article-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2023-03-27T08:18:33.460Z" title="更新于 2023-03-27 16:18:33">2023-03-27</time></span><span class="article-meta"><span class="article-meta-separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/categories/Android/">Android</a><i class="fas fa-angle-right article-meta-link"></i><a class="article-meta__categories" href="/categories/Android/Kotlin/">Kotlin</a><i class="fas fa-angle-right article-meta-link"></i><a class="article-meta__categories" href="/categories/Android/Kotlin/Kotlin%E7%BC%96%E7%A8%8B%E7%AC%AC%E4%B8%80%E8%AF%BE/">Kotlin编程第一课</a></span><span class="article-meta tags"><span class="article-meta-separator">|</span><i class="fas fa-tag"></i><a class="article-meta__tags" href="/tags/Kotlin/">Kotlin</a></span></div><div class="content">基础篇Kotlin编程第一课–(基础篇)01  Kotlin基础语法：正式开启学习之旅Kotlin编程第一课–(基础篇)02  面向对象：理解Kotlin设计者的良苦用心Kotlin编程第一课–(基础篇)03  Kotlin原理：编译器在幕后干了哪些“好事”？Kotlin编程第一课–(基础篇)04 | 实战：构建一个Kotlin版本的四则运算计算器Kotlin编程第一课–(基础篇)05  object关键字：你到底有多少种用法？Kotlin编程第一课–(基础篇)06  扩展：你的能力边界到底在哪里？Kotlin编程第一课–(基础篇)07  高阶函数：为什么说函数是Kotlin的“一等公民”？Kotlin编程第一课–(基础篇)08  实战：用Kotlin写一个英语词频统计程序Kotlin编程第一课–(基础篇)加餐一  初识Kotlin函数式编程Kotlin编程第一课–(基础篇)09  委托：你为何总是被低估？Kotlin编程第一课–(基础篇)10  泛型：逆变or协变，傻傻分不清？Kotlin编程第一课–(基础篇)11  注解与反射：进阶必备技能Kotlin编程第一课–(基础篇)12   ...</div></div></div><div class="recent-post-item"><div class="post_cover left"><a href="/posts/58999c28/" title="Kotlin编程第一课--(Android项目篇)35  用Kotlin写一个GitHub Trending App"><img class="post-bg" src="https://www.gaoguang.com/uploads/allimg/201015/2-201015120J1.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Kotlin编程第一课--(Android项目篇)35  用Kotlin写一个GitHub Trending App"></a></div><div class="recent-post-info"><a class="article-title" href="/posts/58999c28/" title="Kotlin编程第一课--(Android项目篇)35  用Kotlin写一个GitHub Trending App">Kotlin编程第一课--(Android项目篇)35  用Kotlin写一个GitHub Trending App</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time class="post-meta-date-created" datetime="2022-07-03T03:02:12.000Z" title="发表于 2022-07-03 11:02:12">2022-07-03</time><span class="article-meta-separator">|</span><i class="fas fa-history"></i><span class="article-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2023-03-23T08:23:22.651Z" title="更新于 2023-03-23 16:23:22">2023-03-23</time></span><span class="article-meta"><span class="article-meta-separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/categories/Android/">Android</a><i class="fas fa-angle-right article-meta-link"></i><a class="article-meta__categories" href="/categories/Android/Kotlin/">Kotlin</a><i class="fas fa-angle-right article-meta-link"></i><a class="article-meta__categories" href="/categories/Android/Kotlin/Kotlin%E7%BC%96%E7%A8%8B%E7%AC%AC%E4%B8%80%E8%AF%BE/">Kotlin编程第一课</a></span><span class="article-meta tags"><span class="article-meta-separator">|</span><i class="fas fa-tag"></i><a class="article-meta__tags" href="/tags/Kotlin/">Kotlin</a></span></div><div class="content">这节课，我们一起来用 Kotlin 和 Jetpack 写一个简单的 Android 应用。为了便于理解，这个应用的功能会尽量简单，即使你对 Android 不是特别熟悉，跟着课程的引导，你也能轻松完成。
准备工作在之前的课程中，我们的实战项目都是基于 JVM 的，并没有涉及过 Android 相关的配置。因此，如果你的电脑没有 Android 开发的环境的话，那么可能需要做一些额外的配置。当然，在你已有 Java 环境的前提下，想要配置 Android 开发环境并不麻烦，你可以去搜索一些相关的Android 开发环境配置的教程。
那么，要进行 Android 开发，我们可以使用 IntelliJ，也可以使用 Android Studio，后者针对 Android 开发做了很多定制化，也是免费的，这里我也建议你去下载 Android Studio。
当配置好所有的环境以后，我们就可以像创建 Kotlin 工程一样，来创建一个新的 Android 工程了。

然后，当你创建好工程以后，就可以尝试运行代码了，这时候你大概率会看到一个 Hello World 的初始界面。
接下来，我们就正式 ...</div></div></div><div class="recent-post-item"><div class="post_cover right"><a href="/posts/b63f0842/" title="Kotlin编程第一课--(Android项目篇)34  Kotlin与Jetpack简直是天生一对！"><img class="post-bg" src="https://s2.loli.net/2023/03/14/ViqYvHWes9C2f6J.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Kotlin编程第一课--(Android项目篇)34  Kotlin与Jetpack简直是天生一对！"></a></div><div class="recent-post-info"><a class="article-title" href="/posts/b63f0842/" title="Kotlin编程第一课--(Android项目篇)34  Kotlin与Jetpack简直是天生一对！">Kotlin编程第一课--(Android项目篇)34  Kotlin与Jetpack简直是天生一对！</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time class="post-meta-date-created" datetime="2022-07-02T01:58:04.000Z" title="发表于 2022-07-02 09:58:04">2022-07-02</time><span class="article-meta-separator">|</span><i class="fas fa-history"></i><span class="article-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2023-03-23T08:02:42.145Z" title="更新于 2023-03-23 16:02:42">2023-03-23</time></span><span class="article-meta"><span class="article-meta-separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/categories/Android/">Android</a><i class="fas fa-angle-right article-meta-link"></i><a class="article-meta__categories" href="/categories/Android/Kotlin/">Kotlin</a><i class="fas fa-angle-right article-meta-link"></i><a class="article-meta__categories" href="/categories/Android/Kotlin/Kotlin%E7%BC%96%E7%A8%8B%E7%AC%AC%E4%B8%80%E8%AF%BE/">Kotlin编程第一课</a></span><span class="article-meta tags"><span class="article-meta-separator">|</span><i class="fas fa-tag"></i><a class="article-meta__tags" href="/tags/Kotlin/">Kotlin</a></span></div><div class="content">今天，我们来聊聊 Android 的 Jetpack。
在我看来，Kotlin 和 Jetpack，它们两个简直就是天生一对。作为 Android 开发者，如果只用 Kotlin 不用 Jetpack，我们其实很难在 Android 平台充分发挥 Kotlin 的语言优势。而如果我们只用 Jetpack 而不用 Kotlin，那么，我们将只能用到 Jetpack 的小部分功能。毕竟，Jetpack 当中有很多 API 和库，是专门为 Kotlin 提供的。
经过前面课程内容的学习，相信现在你已经对 Kotlin 十分熟悉了，那么，接下来就让我们来看看 Jetpack 吧！这节课里，我会为你介绍 Jetpack 核心库的基本概念、简单用法，以及它跟 Kotlin 之间的关系，从而也为我们下节课的实战项目打下基础。
Jetpack 简介Jetpack，它有“喷气式背包”的意思。对于我们开发者来说，它其实就是 Google 官方为我们提供的一套开发套件，专门用来帮助 Android 开发者提升开发效率、提升应用稳定性的。

Android Jetpack，最初的宣传图标，就是“穿着喷气式背包 ...</div></div></div><div class="recent-post-item"><div class="post_cover left"><a href="/posts/11a43e5b/" title="Kotlin编程第一课--(Android项目篇)33 Java Android开发者还会有未来吗？"><img class="post-bg" src="https://img2.baidu.com/it/u=2147165840,2215518645&amp;fm=253&amp;fmt=auto&amp;app=138&amp;f=JPEG?w=500&amp;h=889" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Kotlin编程第一课--(Android项目篇)33 Java Android开发者还会有未来吗？"></a></div><div class="recent-post-info"><a class="article-title" href="/posts/11a43e5b/" title="Kotlin编程第一课--(Android项目篇)33 Java Android开发者还会有未来吗？">Kotlin编程第一课--(Android项目篇)33 Java Android开发者还会有未来吗？</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time class="post-meta-date-created" datetime="2022-07-01T01:45:42.000Z" title="发表于 2022-07-01 09:45:42">2022-07-01</time><span class="article-meta-separator">|</span><i class="fas fa-history"></i><span class="article-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2023-03-23T08:02:04.010Z" title="更新于 2023-03-23 16:02:04">2023-03-23</time></span><span class="article-meta"><span class="article-meta-separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/categories/Android/">Android</a><i class="fas fa-angle-right article-meta-link"></i><a class="article-meta__categories" href="/categories/Android/Kotlin/">Kotlin</a><i class="fas fa-angle-right article-meta-link"></i><a class="article-meta__categories" href="/categories/Android/Kotlin/Kotlin%E7%BC%96%E7%A8%8B%E7%AC%AC%E4%B8%80%E8%AF%BE/">Kotlin编程第一课</a></span><span class="article-meta tags"><span class="article-meta-separator">|</span><i class="fas fa-tag"></i><a class="article-meta__tags" href="/tags/Kotlin/">Kotlin</a></span></div><div class="content">
在过去的几十讲里，我们把 Kotlin 的基础语法和核心难点协程，都全面学习了一遍，从原理到实战，从协程的核心挂起函数、launch 等，到探究它们的源码定义，可以说我们已经基本掌握了 Kotlin 的核心知识点与特性，你也应该可以在工作中使用 Kotlin 来解决实际问题了。如果你发现自己对这些知识的掌握还有不少漏洞，也别着急，可以再回头复习一下相应部分的内容，或者在留言区提问，我会给你解答。
那么，从这节课起，我会带你来看看 Kotlin 在实践场景中，应用得最普遍、最广泛的领域，Android。我们一起来学习下如何结合所学的 Kotlin 知识，来高效开发 Android 应用。
今天这节课，我们先来聊聊 Kotlin 和 Android 的关系，让你对 Android 的现状与未来的发展方向有一个清晰的认识。
虽然 Kotlin 是面向多个平台的（如 JVM、Native、JS 等），不过我们在讨论 Kotlin 的同时，难免也会讨论下 Android。甚至，很多开发者都是因为 Android 才开始接触 Kotlin 的。
说起 Kotlin 与 Android，就不得不提 ...</div></div></div><div class="recent-post-item"><div class="post_cover right"><a href="/posts/11989076/" title="Kotlin编程第一课--(源码篇)32  图解Flow：原来你是只纸老虎？"><img class="post-bg" src="https://s2.loli.net/2023/03/14/gTnEJuoxODYvCcm.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Kotlin编程第一课--(源码篇)32  图解Flow：原来你是只纸老虎？"></a></div><div class="recent-post-info"><a class="article-title" href="/posts/11989076/" title="Kotlin编程第一课--(源码篇)32  图解Flow：原来你是只纸老虎？">Kotlin编程第一课--(源码篇)32  图解Flow：原来你是只纸老虎？</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time class="post-meta-date-created" datetime="2022-06-29T01:39:04.000Z" title="发表于 2022-06-29 09:39:04">2022-06-29</time><span class="article-meta-separator">|</span><i class="fas fa-history"></i><span class="article-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2023-03-23T08:00:31.375Z" title="更新于 2023-03-23 16:00:31">2023-03-23</time></span><span class="article-meta"><span class="article-meta-separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/categories/Android/">Android</a><i class="fas fa-angle-right article-meta-link"></i><a class="article-meta__categories" href="/categories/Android/Kotlin/">Kotlin</a><i class="fas fa-angle-right article-meta-link"></i><a class="article-meta__categories" href="/categories/Android/Kotlin/Kotlin%E7%BC%96%E7%A8%8B%E7%AC%AC%E4%B8%80%E8%AF%BE/">Kotlin编程第一课</a></span><span class="article-meta tags"><span class="article-meta-separator">|</span><i class="fas fa-tag"></i><a class="article-meta__tags" href="/tags/Kotlin/">Kotlin</a></span></div><div class="content">
今天我们来研究 Flow 的源代码。
经过前面的学习，我们已经知道了，Channel 和 Flow 都是数据流，Channel 是“热”的，Flow 则是“冷”的。这里的冷，代表着 Flow 不仅是“冷淡”的，而且还是“懒惰”的。
除了“冷”这个特性以外，Flow 从 API 的角度分类，主要分为：构造器、中间操作符、终止操作符。今天这节课，我们将会从这几个角度来分析 Flow 的源码，来看看它的这几类 API 是如何实现的。
经过这节课的学习，你会发现：虽然 Flow 的功能看起来非常高大上，然而它的原理却非常的简单，是一只名副其实的“纸老虎”。
Flow 为什么是冷的？在正式开始研究 Flow 源代码之前，我们首先需要确定研究的对象。这里，我写了一段 Demo 代码，接下来我们就以这个 Demo 为例，来分析 Flow 的整个执行流程：
// 代码段1fun main() &#123;    val scope = CoroutineScope(Job())    scope.launch &#123;        testFlow()    &#125;    Thread. ...</div></div></div><div class="recent-post-item"><div class="post_cover left"><a href="/posts/6017bcef/" title="Kotlin编程第一课--(源码篇)31  图解Channel：如何理解它的CSP通信模型？"><img class="post-bg" src="https://www.gaoguang.com/uploads/allimg/201015/2-201015120J1-51.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Kotlin编程第一课--(源码篇)31  图解Channel：如何理解它的CSP通信模型？"></a></div><div class="recent-post-info"><a class="article-title" href="/posts/6017bcef/" title="Kotlin编程第一课--(源码篇)31  图解Channel：如何理解它的CSP通信模型？">Kotlin编程第一课--(源码篇)31  图解Channel：如何理解它的CSP通信模型？</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time class="post-meta-date-created" datetime="2022-06-28T09:25:39.000Z" title="发表于 2022-06-28 17:25:39">2022-06-28</time><span class="article-meta-separator">|</span><i class="fas fa-history"></i><span class="article-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2023-03-23T08:00:36.081Z" title="更新于 2023-03-23 16:00:36">2023-03-23</time></span><span class="article-meta"><span class="article-meta-separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/categories/Android/">Android</a><i class="fas fa-angle-right article-meta-link"></i><a class="article-meta__categories" href="/categories/Android/Kotlin/">Kotlin</a><i class="fas fa-angle-right article-meta-link"></i><a class="article-meta__categories" href="/categories/Android/Kotlin/Kotlin%E7%BC%96%E7%A8%8B%E7%AC%AC%E4%B8%80%E8%AF%BE/">Kotlin编程第一课</a></span><span class="article-meta tags"><span class="article-meta-separator">|</span><i class="fas fa-tag"></i><a class="article-meta__tags" href="/tags/Kotlin/">Kotlin</a></span></div><div class="content">今天我们来分析 Channel 的源码。
Kotlin 的 Channel 是一个非常重要的组件，在它出现之前，协程之间很难进行通信，有了它以后，协程之间的通信就轻而易举了。在第 22 讲当中，我们甚至还借助 Channel 实现的 Actor 做到了并发安全。
那么总的来说，Channel 是热的，同时它还是一个线程安全的数据管道。而由于 Channel 具有线程安全的特性，因此，它最常见的用法，就是建立 CSP 通信模型（Communicating Sequential Processes）。
不过你可能会觉得，CSP 太抽象了不好理解，但其实，这个通信模型我们在第 22 讲里就接触过了。当时我们虽然是通过 Actor 来实现的，但却是把它当作 CSP 在用，它们两者的差异其实很小。
关于CSP 的理论，它的精确定义其实比较复杂，不过它的核心理念用一句话就可以概括：不要共享内存来通信；而是要用通信来共享内存（Don’t communicate by sharing memory; share memory by communicating）。
可是，我们为什么可以通过 Channe ...</div></div></div><div class="recent-post-item"><div class="post_cover right"><a href="/posts/4f3df7f8/" title="Kotlin编程第一课--(源码篇)30  CoroutineScope是如何管理协程的？"><img class="post-bg" src="https://s2.loli.net/2023/03/14/se3pdS2JL7aIHPg.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Kotlin编程第一课--(源码篇)30  CoroutineScope是如何管理协程的？"></a></div><div class="recent-post-info"><a class="article-title" href="/posts/4f3df7f8/" title="Kotlin编程第一课--(源码篇)30  CoroutineScope是如何管理协程的？">Kotlin编程第一课--(源码篇)30  CoroutineScope是如何管理协程的？</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time class="post-meta-date-created" datetime="2022-06-27T09:17:07.000Z" title="发表于 2022-06-27 17:17:07">2022-06-27</time><span class="article-meta-separator">|</span><i class="fas fa-history"></i><span class="article-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2023-03-23T08:00:41.010Z" title="更新于 2023-03-23 16:00:41">2023-03-23</time></span><span class="article-meta"><span class="article-meta-separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/categories/Android/">Android</a><i class="fas fa-angle-right article-meta-link"></i><a class="article-meta__categories" href="/categories/Android/Kotlin/">Kotlin</a><i class="fas fa-angle-right article-meta-link"></i><a class="article-meta__categories" href="/categories/Android/Kotlin/Kotlin%E7%BC%96%E7%A8%8B%E7%AC%AC%E4%B8%80%E8%AF%BE/">Kotlin编程第一课</a></span><span class="article-meta tags"><span class="article-meta-separator">|</span><i class="fas fa-tag"></i><a class="article-meta__tags" href="/tags/Kotlin/">Kotlin</a></span></div><div class="content">通过前面课程的学习，我们知道 CoroutineScope 是实现协程结构化并发的关键。使用 CoroutineScope，我们可以批量管理同一个作用域下面所有的协程。那么，今天这节课，我们就来研究一下 CoroutineScope 是如何管理协程的。
CoroutineScope VS 结构化并发在前面的课程中，我们学习过 CoroutineScope 的用法。由于 launch、async 被定义成了 CoroutineScope 的扩展函数，这就意味着：在调用 launch 之前，我们必须先获取 CoroutineScope。
// 代码段1public fun CoroutineScope.launch(    context: CoroutineContext = EmptyCoroutineContext,    start: CoroutineStart = CoroutineStart.DEFAULT,    block: suspend CoroutineScope.() -&gt; Unit): Job &#123;&#125;public fun &lt;T&gt ...</div></div></div><div class="recent-post-item"><div class="post_cover left"><a href="/posts/c0627888/" title="Kotlin编程第一课--(源码篇)29  Dispatchers是如何工作的？"><img class="post-bg" src="https://pic.rmb.bdstatic.com/18ec2a58fd6a2bac0c819d31ee46e2a3.jpeg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Kotlin编程第一课--(源码篇)29  Dispatchers是如何工作的？"></a></div><div class="recent-post-info"><a class="article-title" href="/posts/c0627888/" title="Kotlin编程第一课--(源码篇)29  Dispatchers是如何工作的？">Kotlin编程第一课--(源码篇)29  Dispatchers是如何工作的？</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time class="post-meta-date-created" datetime="2022-06-26T09:06:40.000Z" title="发表于 2022-06-26 17:06:40">2022-06-26</time><span class="article-meta-separator">|</span><i class="fas fa-history"></i><span class="article-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2023-03-23T08:00:46.073Z" title="更新于 2023-03-23 16:00:46">2023-03-23</time></span><span class="article-meta"><span class="article-meta-separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/categories/Android/">Android</a><i class="fas fa-angle-right article-meta-link"></i><a class="article-meta__categories" href="/categories/Android/Kotlin/">Kotlin</a><i class="fas fa-angle-right article-meta-link"></i><a class="article-meta__categories" href="/categories/Android/Kotlin/Kotlin%E7%BC%96%E7%A8%8B%E7%AC%AC%E4%B8%80%E8%AF%BE/">Kotlin编程第一课</a></span><span class="article-meta tags"><span class="article-meta-separator">|</span><i class="fas fa-tag"></i><a class="article-meta__tags" href="/tags/Kotlin/">Kotlin</a></span></div><div class="content">今天，我们来分析 Kotlin 协程当中的 Dispatchers。
上节课里，我们分析了 launch 的源代码，从中我们知道，Kotlin 的 launch 会调用 startCoroutineCancellable()，接着又会调用 createCoroutineUnintercepted()，最终会调用编译器帮我们生成 SuspendLambda 实现类当中的 create() 方法。这样，协程就创建出来了。不过，协程是创建出来了，可它是如何运行的呢？
另外我们也都知道，协程无法脱离线程运行，Kotlin 当中所有的协程，最终都是运行在线程之上的。那么，协程创建出来以后，它又是如何跟线程产生关联的？这节课，我们将进一步分析 launch 的启动流程，去发掘上节课我们忽略掉的代码分支。
我相信，经过这节课的学习，你会对协程与线程之间的关系有一个更加透彻的认识。
Dispatchers在上节课里我们学习过，launch{}本质上是调用了 startCoroutineCancellable() 当中的 createCoroutineUnintercepted() 方法创建了协程。
/ ...</div></div></div><div class="recent-post-item"><div class="post_cover right"><a href="/posts/4c362f78/" title="Kotlin编程第一课--(源码篇)加餐五  深入理解协程基础元素"><img class="post-bg" src="https://img.tt98.com/d/file/pic/2018060523545937/5b15f4a26c32b.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Kotlin编程第一课--(源码篇)加餐五  深入理解协程基础元素"></a></div><div class="recent-post-info"><a class="article-title" href="/posts/4c362f78/" title="Kotlin编程第一课--(源码篇)加餐五  深入理解协程基础元素">Kotlin编程第一课--(源码篇)加餐五  深入理解协程基础元素</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time class="post-meta-date-created" datetime="2022-06-25T08:44:21.000Z" title="发表于 2022-06-25 16:44:21">2022-06-25</time><span class="article-meta-separator">|</span><i class="fas fa-history"></i><span class="article-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2023-03-23T08:00:51.512Z" title="更新于 2023-03-23 16:00:51">2023-03-23</time></span><span class="article-meta"><span class="article-meta-separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/categories/Android/">Android</a><i class="fas fa-angle-right article-meta-link"></i><a class="article-meta__categories" href="/categories/Android/Kotlin/">Kotlin</a><i class="fas fa-angle-right article-meta-link"></i><a class="article-meta__categories" href="/categories/Android/Kotlin/Kotlin%E7%BC%96%E7%A8%8B%E7%AC%AC%E4%B8%80%E8%AF%BE/">Kotlin编程第一课</a></span><span class="article-meta tags"><span class="article-meta-separator">|</span><i class="fas fa-tag"></i><a class="article-meta__tags" href="/tags/Kotlin/">Kotlin</a></span></div><div class="content">在上一讲当中，我们深入研究了 Kotlin 挂起函数的原理，实际更多的是在了解协程的“基础层”。而接下来，我们将会开始研究协程启动的原理，探索协程的“中间层”。
在第 26 讲里，我曾提到过，Kotlin 的协程框架其实就是协程基础元素组合出来的框架。如果我们想要弄懂 Kotlin 协程，首先就要将它的“基础层”理解透彻。
所以今天，我还是决定来一次加餐，带你系统深入地认识一下 Kotlin 协程当中的基础元素。等你对协程的基础层有了深入认识以后，下节课研究协程启动原理就会轻松一些了。
协程基础元素通过第 26 讲我们现在已经知道，Kotlin 协程的基础元素大致有这些：Continuation、SafeContinuation、CoroutineContext、CombinedContext、CancellationException、intrinsics。


其中的 CoroutineContext、CancellationException 我都已经介绍过了，另外的 CombinedContext，其实就是 CoroutineContext 的一个实现类，而 SafeConti ...</div></div></div><nav id="pagination"><div class="pagination"><a class="extend prev" rel="prev" href="/page/9/#content-inner"><i class="fas fa-chevron-left fa-fw"></i></a><a class="page-number" href="/">1</a><span class="space">&hellip;</span><a class="page-number" href="/page/9/#content-inner">9</a><span class="page-number current">10</span><a class="page-number" href="/page/11/#content-inner">11</a><span class="space">&hellip;</span><a class="page-number" href="/page/17/#content-inner">17</a><a class="extend next" rel="next" href="/page/11/#content-inner"><i class="fas fa-chevron-right fa-fw"></i></a></div></nav></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="is-center"><div class="avatar-img"><img src="https://s2.loli.net/2023/03/09/QrI9mgJ4XlbEPzN.png" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"/></div><div class="author-info__name">Carl Su</div><div class="author-info__description">纸上得来终觉浅，绝知此事要躬行。</div></div><div class="card-info-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">169</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">37</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">38</div></a></div><a id="card-info-btn" target="_blank" rel="noopener" href="https://github.com/xxxxxx"><i class="fab fa-github"></i><span>Follow Me</span></a><div class="card-info-social-icons is-center"><a class="social-icon" href="https://github.com/winstone-su" target="_blank" title="Github"><i class="fab fa-github"></i></a><a class="social-icon" href="mailto:winstone.su@gmail.com" target="_blank" title="Email"><i class="fas fa-envelope"></i></a></div></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn fa-shake"></i><span>公告</span></div><div class="announcement_content">学习如逆水行舟，不进则退。</div></div><div class="sticky_layout"><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item"><a class="thumbnail" href="/posts/7098ebd6/" title="2023-03-30-Windows下PowerShell自定义函数"><img src="https://s2.loli.net/2023/03/30/6ilJQwW3T2e89xy.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="2023-03-30-Windows下PowerShell自定义函数"/></a><div class="content"><a class="title" href="/posts/7098ebd6/" title="2023-03-30-Windows下PowerShell自定义函数">2023-03-30-Windows下PowerShell自定义函数</a><time datetime="2023-03-30T01:57:31.000Z" title="发表于 2023-03-30 09:57:31">2023-03-30</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/posts/e6af74ea/" title="2023-03-30-Funny Github">2023-03-30-Funny Github</a><time datetime="2023-03-30T01:12:25.000Z" title="发表于 2023-03-30 09:12:25">2023-03-30</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/posts/7028d55e/" title="2023-03-29-CE修改器加速百度网盘下载"><img src="https://img1.mydrivers.com/img/20210916/ecbb517f-6cd5-438f-9efc-98e9973eece3.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="2023-03-29-CE修改器加速百度网盘下载"/></a><div class="content"><a class="title" href="/posts/7028d55e/" title="2023-03-29-CE修改器加速百度网盘下载">2023-03-29-CE修改器加速百度网盘下载</a><time datetime="2023-03-29T01:48:38.000Z" title="发表于 2023-03-29 09:48:38">2023-03-29</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/posts/bf1f0a14/" title="2023-03-27-Hilt基本用法">2023-03-27-Hilt基本用法</a><time datetime="2023-03-27T09:14:16.000Z" title="发表于 2023-03-27 17:14:16">2023-03-27</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/posts/6f434e78/" title="2023-03-23-CentOS新建定时任务"><img src="https://s2.loli.net/2023/03/23/KLmkEbpJArO4z1H.webp" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="2023-03-23-CentOS新建定时任务"/></a><div class="content"><a class="title" href="/posts/6f434e78/" title="2023-03-23-CentOS新建定时任务">2023-03-23-CentOS新建定时任务</a><time datetime="2023-03-23T03:08:39.000Z" title="发表于 2023-03-23 11:08:39">2023-03-23</time></div></div></div></div><div class="card-widget card-categories"><div class="item-headline">
            <i class="fas fa-folder-open"></i>
            <span>分类</span>
            <a class="card-more-btn" href="/categories/" title="查看更多">
    <i class="fas fa-angle-right"></i></a>
            </div>
            <ul class="card-category-list" id="aside-cat-list">
            <li class="card-category-list-item "><a class="card-category-list-link" href="/categories/AI/"><span class="card-category-list-name">AI</span><span class="card-category-list-count">1</span></a></li><li class="card-category-list-item "><a class="card-category-list-link" href="/categories/Android/"><span class="card-category-list-name">Android</span><span class="card-category-list-count">100</span></a><ul class="card-category-list child"><li class="card-category-list-item "><a class="card-category-list-link" href="/categories/Android/Jetpack/"><span class="card-category-list-name">Jetpack</span><span class="card-category-list-count">13</span></a></li><li class="card-category-list-item "><a class="card-category-list-link" href="/categories/Android/Kotlin/"><span class="card-category-list-name">Kotlin</span><span class="card-category-list-count">67</span></a><ul class="card-category-list child"><li class="card-category-list-item "><a class="card-category-list-link" href="/categories/Android/Kotlin/Coroutine/"><span class="card-category-list-name">Coroutine</span><span class="card-category-list-count">2</span></a></li><li class="card-category-list-item "><a class="card-category-list-link" href="/categories/Android/Kotlin/Foundation/"><span class="card-category-list-name">Foundation</span><span class="card-category-list-count">16</span></a></li><li class="card-category-list-item "><a class="card-category-list-link" href="/categories/Android/Kotlin/Kotlin%E7%BC%96%E7%A8%8B%E7%AC%AC%E4%B8%80%E8%AF%BE/"><span class="card-category-list-name">Kotlin编程第一课</span><span class="card-category-list-count">48</span></a></li></ul></li><li class="card-category-list-item "><a class="card-category-list-link" href="/categories/Android/%E8%87%AA%E5%AE%9A%E4%B9%89View/"><span class="card-category-list-name">自定义View</span><span class="card-category-list-count">4</span></a></li></ul></li>
            </ul></div><div class="card-widget card-tags"><div class="item-headline"><i class="fas fa-tags"></i><span>标签</span></div><div class="card-tag-cloud"><a href="/tags/Kotlin/" style="font-size: 1.45em; color: rgb(195, 93, 54)">Kotlin</a><a href="/tags/git/" style="font-size: 1.18em; color: rgb(135, 190, 174)">git</a><a href="/tags/Android/" style="font-size: 1.42em; color: rgb(101, 90, 154)">Android</a><a href="/tags/JitPack/" style="font-size: 1.15em; color: rgb(143, 142, 114)">JitPack</a><a href="/tags/Retrofit/" style="font-size: 1.15em; color: rgb(90, 150, 44)">Retrofit</a><a href="/tags/Hexo/" style="font-size: 1.32em; color: rgb(51, 109, 10)">Hexo</a><a href="/tags/Markdown/" style="font-size: 1.18em; color: rgb(133, 57, 59)">Markdown</a><a href="/tags/iOS/" style="font-size: 1.35em; color: rgb(121, 123, 114)">iOS</a><a href="/tags/MacOS/" style="font-size: 1.18em; color: rgb(10, 35, 122)">MacOS</a><a href="/tags/Http/" style="font-size: 1.15em; color: rgb(94, 39, 115)">Http</a><a href="/tags/Python/" style="font-size: 1.25em; color: rgb(45, 148, 172)">Python</a><a href="/tags/jekyll/" style="font-size: 1.15em; color: rgb(85, 108, 165)">jekyll</a><a href="/tags/Jekyll/" style="font-size: 1.15em; color: rgb(170, 25, 64)">Jekyll</a><a href="/tags/postman/" style="font-size: 1.15em; color: rgb(61, 161, 159)">postman</a><a href="/tags/AI/" style="font-size: 1.15em; color: rgb(7, 49, 2)">AI</a><a href="/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/" style="font-size: 1.22em; color: rgb(135, 140, 105)">设计模式</a><a href="/tags/jenkins/" style="font-size: 1.15em; color: rgb(194, 115, 151)">jenkins</a><a href="/tags/linux/" style="font-size: 1.15em; color: rgb(138, 124, 34)">linux</a><a href="/tags/Charles/" style="font-size: 1.15em; color: rgb(128, 13, 38)">Charles</a><a href="/tags/harmmony/" style="font-size: 1.15em; color: rgb(171, 37, 138)">harmmony</a><a href="/tags/google-services/" style="font-size: 1.15em; color: rgb(28, 164, 123)">google services</a><a href="/tags/Selenium/" style="font-size: 1.15em; color: rgb(134, 3, 111)">Selenium</a><a href="/tags/Jetpack/" style="font-size: 1.38em; color: rgb(16, 30, 154)">Jetpack</a><a href="/tags/kotlin/" style="font-size: 1.28em; color: rgb(172, 46, 140)">kotlin</a><a href="/tags/gradle/" style="font-size: 1.15em; color: rgb(21, 115, 7)">gradle</a><a href="/tags/Android-Studio/" style="font-size: 1.15em; color: rgb(12, 18, 68)">Android Studio</a><a href="/tags/cesium/" style="font-size: 1.18em; color: rgb(26, 81, 37)">cesium</a><a href="/tags/arcgis-for-iOS/" style="font-size: 1.15em; color: rgb(12, 200, 16)">arcgis for iOS</a><a href="/tags/arcgis/" style="font-size: 1.28em; color: rgb(81, 159, 27)">arcgis</a><a href="/tags/Arcgis-for-Android/" style="font-size: 1.15em; color: rgb(59, 79, 47)">Arcgis for Android</a><a href="/tags/Swift/" style="font-size: 1.22em; color: rgb(42, 181, 64)">Swift</a><a href="/tags/Coroutine/" style="font-size: 1.15em; color: rgb(198, 124, 11)">Coroutine</a><a href="/tags/SwiftUI/" style="font-size: 1.22em; color: rgb(1, 175, 42)">SwiftUI</a><a href="/tags/ViewModel/" style="font-size: 1.15em; color: rgb(183, 106, 135)">ViewModel</a><a href="/tags/tools/" style="font-size: 1.15em; color: rgb(31, 78, 33)">tools</a><a href="/tags/github/" style="font-size: 1.15em; color: rgb(121, 106, 125)">github</a><a href="/tags/powershell/" style="font-size: 1.15em; color: rgb(14, 0, 155)">powershell</a></div></div><div class="card-widget card-archives"><div class="item-headline"><i class="fas fa-archive"></i><span>归档</span><a class="card-more-btn" href="/archives/" title="查看更多">
    <i class="fas fa-angle-right"></i></a></div><ul class="card-archive-list"><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2023/03/"><span class="card-archive-list-date">三月 2023</span><span class="card-archive-list-count">22</span></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2023/02/"><span class="card-archive-list-date">二月 2023</span><span class="card-archive-list-count">10</span></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2023/01/"><span class="card-archive-list-date">一月 2023</span><span class="card-archive-list-count">11</span></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2022/12/"><span class="card-archive-list-date">十二月 2022</span><span class="card-archive-list-count">2</span></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2022/11/"><span class="card-archive-list-date">十一月 2022</span><span class="card-archive-list-count">2</span></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2022/10/"><span class="card-archive-list-date">十月 2022</span><span class="card-archive-list-count">3</span></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2022/09/"><span class="card-archive-list-date">九月 2022</span><span class="card-archive-list-count">3</span></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2022/08/"><span class="card-archive-list-date">八月 2022</span><span class="card-archive-list-count">37</span></a></li></ul></div><div class="card-widget card-webinfo"><div class="item-headline"><i class="fas fa-chart-line"></i><span>网站资讯</span></div><div class="webinfo"><div class="webinfo-item"><div class="item-name">文章数目 :</div><div class="item-count">169</div></div><div class="webinfo-item"><div class="item-name">已运行时间 :</div><div class="item-count" id="runtimeshow" data-publishDate="2015-07-07T16:00:00.000Z"><i class="fa-solid fa-spinner fa-spin"></i></div></div><div class="webinfo-item"><div class="item-name">本站总字数 :</div><div class="item-count">289.9k</div></div><div class="webinfo-item"><div class="item-name">本站访客数 :</div><div class="item-count" id="busuanzi_value_site_uv"><i class="fa-solid fa-spinner fa-spin"></i></div></div><div class="webinfo-item"><div class="item-name">本站总访问量 :</div><div class="item-count" id="busuanzi_value_site_pv"><i class="fa-solid fa-spinner fa-spin"></i></div></div><div class="webinfo-item"><div class="item-name">最后更新时间 :</div><div class="item-count" id="last-push-date" data-lastPushDate="2023-03-30T02:59:01.282Z"><i class="fa-solid fa-spinner fa-spin"></i></div></div></div></div></div></div></main><footer id="footer"><div id="footer-wrap"><div class="copyright">&copy;2018 - 2023 By Carl Su</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div><div class="footer_custom_text">学无止境</div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="translateLink" type="button" title="简繁转换">繁</button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button id="chat_btn" type="button" title="聊天"><i class="fas fa-sms"></i></button><button id="go-up" type="button" title="回到顶部"><span class="scroll-percent"></span><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><script src="/js/tw_cn.js"></script><script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox.umd.min.js"></script><script src="https://cdn.jsdelivr.net/npm/vanilla-lazyload/dist/lazyload.iife.min.js"></script><script src="https://cdn.jsdelivr.net/npm/node-snackbar/dist/snackbar.min.js"></script><div class="js-pjax"><script>window.typedJSFn = {
  init: (str) => {
    window.typed = new Typed('#subtitle', Object.assign({
      strings: str,
      startDelay: 300,
      typeSpeed: 150,
      loop: true,
      backSpeed: 50,
    }, null))
  },
  run: (subtitleType) => {
    if (true) {
      if (typeof Typed === 'function') {
        subtitleType()
      } else {
        getScript('https://cdn.jsdelivr.net/npm/typed.js/lib/typed.min.js').then(subtitleType)
      }
    } else {
      subtitleType()
    }
  }
}
</script><script>function subtitleType () {
  if (true) {
    typedJSFn.init(["Better a witty fool than a foolish wit. -- Shakespeare"])
  } else {
    document.getElementById("subtitle").innerHTML = 'Better a witty fool than a foolish wit. -- Shakespeare'
  }
}
typedJSFn.run(subtitleType)</script></div><script defer="defer" id="fluttering_ribbon" mobile="false" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/dist/canvas-fluttering-ribbon.min.js"></script><script src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/dist/activate-power-mode.min.js"></script><script>POWERMODE.colorful = true;
POWERMODE.shake = false;
POWERMODE.mobile = false;
document.body.addEventListener('input', POWERMODE);
</script><script id="click-heart" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/dist/click-heart.min.js" async="async" mobile="false"></script><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script></div><div id="local-search"><div class="search-dialog"><nav class="search-nav"><span class="search-dialog-title">搜索</span><span id="loading-status"></span><button class="search-close-button"><i class="fas fa-times"></i></button></nav><div class="is-center" id="loading-database"><i class="fas fa-spinner fa-pulse"></i><span>  数据库加载中</span></div><div class="search-wrap"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章" type="text"/></div></div><hr/><div id="local-search-results"></div></div></div><div id="search-mask"></div><script src="/js/search/local-search.js"></script></div></body></html>